﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace SiteParser.Core
{
	public class XPathExpressionParser : IExpressionParser
	{
		private const string WILDCARD_SYBMOL = "*";
		private const string xPathNodeRegex = @"([^\\\s\[]+)(\[\s*@([^\\\s\]=]+)\s*=\s*([^\\\s\]]+)\s*\])?";
		private const string selectAttributeXPathRegex = @"(@([^\\\s\]]+)\s*)$";

		#region IExpressionParser Members

		public IList<HtmlNavigationExpression> Parse(string source) {

			var expressionList = new List<HtmlNavigationExpression>();

			Match match = Regex.Match(source, xPathNodeRegex);
			while (match.Success) {
				string node = match.Groups[1].Value;
				if (node.Contains("@")) {
					break;
				}

				string attributeName = match.Groups[3].Value;
				string attributeValue = match.Groups[4].Value;

				HtmlNavigationExpression htmlNavigationExpression = new HtmlNavigationExpression()
				{
					TagMatchingRule = !string.IsNullOrEmpty(node) ? GetMatchingRule(node) : new MatchingRule(),
					SelectType = SelectTypes.InnerHtml,
					AttributesFilter = GetAttributesFilter(attributeName, attributeValue)
				};

				expressionList.Add(htmlNavigationExpression);
				match = match.NextMatch();
			}

			if (Regex.IsMatch(source, selectAttributeXPathRegex) && expressionList.Count > 0)
			{
				expressionList.Last().SelectType = SelectTypes.AttributeValue;
				expressionList.Last().SelectingAttributeName = Regex.Match(source, selectAttributeXPathRegex).Groups[2].Value;
			}

			return expressionList;
		}

		#endregion

		#region Private methods

		IDictionary<string, MatchingRule> GetAttributesFilter(string attributeName, string attributeValue) {
			if (!string.IsNullOrEmpty(attributeName) && !string.IsNullOrEmpty(attributeValue)) {
				IDictionary<string, MatchingRule> attributeFilter = new Dictionary<string, MatchingRule>();
				attributeFilter[attributeName] = GetMatchingRule(attributeValue);
				return attributeFilter;
			}
			else {
				return null;
			}
		}

		private MatchingRule GetMatchingRule(string rawValue) {
			MatchType matchType = MatchType.MatchAll;

			string value = rawValue.Replace(WILDCARD_SYBMOL, string.Empty);

			if (rawValue.Contains(WILDCARD_SYBMOL)) {
				if (rawValue.StartsWith(WILDCARD_SYBMOL) && rawValue.EndsWith(WILDCARD_SYBMOL)) {
					matchType = MatchType.Contain;
				}
				else if (rawValue.EndsWith(WILDCARD_SYBMOL)) {
					matchType = MatchType.StartWith;
				}
				else if (rawValue.StartsWith(WILDCARD_SYBMOL)) {
					matchType = MatchType.EndWith;
				}
			}
			else {
				matchType = !string.IsNullOrEmpty(value) ? MatchType.Direct : MatchType.MatchAll;
			}

			MatchingRule rule = new MatchingRule()
			{
				Name = value,
				Type = matchType
			};

			return rule;
		}

		#endregion Private methods
	}
}
